package com.wiscamp.ninechapters.tags.application.services;

import com.wiscamp.ninechapters.tags.application.assemblers.SubjectAssembler;
import com.wiscamp.ninechapters.tags.application.dto.command.CreateSubjectCommand;
import com.wiscamp.ninechapters.tags.application.dto.command.UpdateSubjectCommand;
import com.wiscamp.ninechapters.tags.application.dto.vo.SubjectVO;
import com.wiscamp.ninechapters.tags.domain.repositories.SubjectRepository;
import com.wiscamp.ninechapters.tags.domain.services.SubjectService;
import cube.ddd.application.BaseAppService;
import cube.ddd.application.command.DeleteCommand;
import cube.ddd.application.command.DisableCommand;
import cube.ddd.application.command.EnableCommand;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.utils.AppServiceUtils;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;

import java.util.Collection;

@Service
public class SubjectAppService extends BaseAppService {

    private final SubjectRepository subjectRepository;

    private final SubjectService subjectService;

    public SubjectAppService(SubjectRepository subjectRepository, SubjectService subjectService) {
        this.subjectRepository = subjectRepository;
        this.subjectService = subjectService;
    }

    @HandleServiceException
    public SubjectVO getSubject(@Min(0) long subjectId) {
        return AppServiceUtils.getById(subjectId, subjectService::getSubject,
                SubjectAssembler.Instance::toSubjectVO);
    }

    @HandleServiceException
    public Collection<SubjectVO> getAvailableSubjects() {
        return AppServiceUtils.getList(subjectRepository::getAvailableSubjects,
                SubjectAssembler.Instance::toSubjectVO);
    }

    @HandleServiceException
    public SubjectVO getSubjectByCode(@NotBlank String subjectCode) {
        return AppServiceUtils.getByText(subjectCode, subjectRepository::getSubjectByCode,
                SubjectAssembler.Instance::toSubjectVO);
    }

    @HandleServiceException
    public Collection<SubjectVO> getSubjectsByName(@NotBlank String subjectName) {
        return AppServiceUtils.getListByText(subjectName, subjectRepository::getSubjectsByName,
                SubjectAssembler.Instance::toSubjectVO);
    }

    @HandleServiceException
    public boolean deleteSubject(@NotNull DeleteCommand command) {
        return AppServiceUtils.delete(command.getId(), getCurrentUserId(), subjectService::deleteSubject);
    }

    @HandleServiceException
    public boolean enableSubject(@NotNull EnableCommand command) {
        return AppServiceUtils.enable(command.getId(), getCurrentUserId(), subjectService::enableSubject);
    }

    @HandleServiceException
    public boolean disableSubject(@NotNull DisableCommand command) {
        return AppServiceUtils.disable(command.getId(), getCurrentUserId(), subjectService::disableSubject);
    }

    @HandleServiceException
    public SubjectVO createSubject(@NotNull CreateSubjectCommand command) {
        return AppServiceUtils.createBy(command, getCurrentUserId(), subjectService::createSubject,
                SubjectAssembler.Instance::toSubjectVO, SubjectAssembler.Instance::fromCreateCommand);
    }

    @HandleServiceException
    public SubjectVO updateSubject(@NotNull UpdateSubjectCommand command) {
        var existSubject = subjectService.getSubject(command.getSubjectId());
        return AppServiceUtils.updateBy(command, existSubject, getCurrentUserId(), subjectService::updateSubject,
                SubjectAssembler.Instance::toSubjectVO, SubjectAssembler.Instance::mergeUpdateCommand);
    }
}
